package org.irri.smta.config.impl;

import java.math.BigDecimal;
import java.math.BigInteger;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;

import org.apache.commons.lang.StringUtils;
import org.irri.smta.config.IConfiguration;
import org.irri.smta.domain.Registry;
import org.irri.smta.repository.IRegistryRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Named("configuration")
public class Configuration implements IConfiguration {

	private static final long serialVersionUID = 1L;
	private static final Logger LOGGER = LoggerFactory
			.getLogger(Configuration.class);

	@Inject
	@Named("registryRepository")
	private IRegistryRepository registryRepository;
	private static Registry registryRoot;

	@PostConstruct
	private void init() {
		LOGGER.debug("init()");
		if (registryRoot == null) {
			LOGGER.debug("Load registry");
			registryRoot = registryRepository
					.findOne(Registry.REGISTRY_ROOT_ID);
		}
	}

	@Override
	public void clear() {
		if (registryRoot != null) {
			if (!registryRoot.getEntries().isEmpty()) {
				registryRoot.getEntries().clear();
			}
		}
		registryRoot = null;
	}

	@Override
	public Boolean containsKey(String key) {
		Registry registry = findRegistryByKey(key);
		return registry != null;
	}

	@Override
	public BigDecimal getBigDecimal(String key) {
		Registry registry = findRegistryByKey(key);
		if (registry != null) {
			String value = registry.getValue();
			if (value != null) {
				return new BigDecimal(value);
			}
		}
		return null;
	}

	@Override
	public BigDecimal getBigDecimal(String key, BigDecimal defaultValue) {
		BigDecimal value = getBigDecimal(key);
		if (value != null) {
			return value;
		}
		return defaultValue;
	}

	@Override
	public BigInteger getBigInteger(String key) {
		Registry registry = findRegistryByKey(key);
		if (registry != null) {
			String value = registry.getValue();
			if (value != null) {
				return new BigInteger(value);
			}
		}
		return null;
	}

	@Override
	public BigInteger getBigInteger(String key, BigInteger defaultValue) {
		BigInteger value = getBigInteger(key);
		if (value != null) {
			return value;
		}
		return defaultValue;
	}

	@Override
	public Boolean getBoolean(String key) {
		Registry registry = findRegistryByKey(key);
		if (registry != null) {
			String value = registry.getValue();
			if (value != null) {
				return new Boolean(value);
			}
		}
		return null;
	}

	@Override
	public Boolean getBoolean(String key, Boolean defaultValue) {
		Boolean value = getBoolean(key);
		if (value != null) {
			return value;
		}
		return defaultValue;
	}

	@Override
	public Byte getByte(String key) {
		Registry registry = findRegistryByKey(key);
		if (registry != null) {
			String value = registry.getValue();
			if (value != null) {
				return new Byte(value);
			}
		}
		return null;
	}

	@Override
	public Byte getByte(String key, Byte defaultValue) {
		Byte value = getByte(key);
		if (value != null) {
			return value;
		}
		return defaultValue;
	}

	@Override
	public Double getDouble(String key) {
		Registry registry = findRegistryByKey(key);
		if (registry != null) {
			String value = registry.getValue();
			if (value != null) {
				return new Double(value);
			}
		}
		return null;
	}

	@Override
	public Double getDouble(String key, Double defaultValue) {
		Double value = getDouble(key);
		if (value != null) {
			return value;
		}
		return defaultValue;
	}

	@Override
	public Float getFloat(String key) {
		Registry registry = findRegistryByKey(key);
		if (registry != null) {
			String value = registry.getValue();
			if (value != null) {
				return new Float(value);
			}
		}
		return null;
	}

	@Override
	public Float getFloat(String key, Float defaultValue) {
		Float value = getFloat(key);
		if (value != null) {
			return value;
		}
		return defaultValue;
	}

	@Override
	public Integer getInteger(String key) {
		Registry registry = findRegistryByKey(key);
		if (registry != null) {
			String value = registry.getValue();
			if (value != null) {
				return new Integer(value);
			}
		}
		return null;
	}

	@Override
	public Integer getInteger(String key, Integer defaultValue) {
		Integer value = getInteger(key);
		if (value != null) {
			return value;
		}
		return defaultValue;
	}

	@Override
	public Long getLong(String key) {
		Registry registry = findRegistryByKey(key);
		if (registry != null) {
			String value = registry.getValue();
			if (value != null) {
				return new Long(value);
			}
		}
		return null;
	}

	@Override
	public Long getLong(String key, Long defaultValue) {
		Long value = getLong(key);
		if (value != null) {
			return value;
		}
		return defaultValue;
	}

	@Override
	public Short getShort(String key) {
		Registry registry = findRegistryByKey(key);
		if (registry != null) {
			String value = registry.getValue();
			if (value != null) {
				return new Short(value);
			}
		}
		return null;
	}

	@Override
	public Short getShort(String key, Short defaultValue) {
		Short value = getShort(key);
		if (value != null) {
			return value;
		}
		return defaultValue;
	}

	@Override
	public String getString(String key) {
		Registry registry = findRegistryByKey(key);
		if (registry != null) {
			String value = registry.getValue();
			if (value != null) {
				return new String(value);
			}
		}
		return null;
	}

	@Override
	public String getString(String key, String defaultValue) {
		String value = getString(key);
		if (value != null) {
			return value;
		}
		return defaultValue;
	}

	@Override
	public Boolean isEmpty() {
		return registryRoot == null;
	}

	@Override
	public void load() {
		clear();
		registryRoot = registryRepository.findOne(Registry.REGISTRY_ROOT_ID);
	}

	private Registry findRegistryByKey(String key) {
		if (registryRoot == null || StringUtils.isEmpty(key)) {
			return null;
		}

		String[] names = key.split(Registry.PATH_SEPARATOR);

		Registry registry = registryRoot;
		for (String name : names) {
			if (!StringUtils.isEmpty(name)) {
				registry = resolveName(registry, name);
				if (registry == null) {
					return null;
				}
			}
		}
		return registry;
	}

	private Registry resolveName(Registry registry, String name) {
		for (Registry entry : registry.getEntries()) {
			if (name.equalsIgnoreCase(entry.getName())) {
				return entry;
			}
		}
		return null;
	}

}
